package controller

import (
	"encoding/json"
	"encoding/xml"
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"reflect"
	"store/libs/helper"
	"store/logic"
	"strings"
)

/**
 * 控制器
 */
type Controller struct {
}

type Response struct {
	Code int         `json:"code" xml:"code"`
	Msg  string      `json:"msg"  xml:"msg"`
	Data interface{} `json:"data" xml:"data"`
}

type xmlResponse struct {
	XMLName  xml.Name `xml:"xmlResponse"`
	Response Response `xml:"response"`
}

/**
 * 格式化校验消息
 */
func (this *Controller) FormatError(input interface{}, err error) error {
	errStr := err.Error()
	errIndex := strings.Index(errStr, "Error:")
	if errIndex < 9 {
		return err
	}

	fields := strings.Split(errStr[6:errIndex-2], ".")
	field, ok := reflect.TypeOf(input).FieldByName(fields[len(fields)-1])
	if !ok {
		return err
	}

	msg := field.Tag.Get("msg")
	if msg == "" {
		return err
	}

	return fmt.Errorf(msg)
}

/**
 * 多协议响应
 */
func (this *Controller) Response(ctx *gin.Context, code int, msg string, data interface{}) {
	resp := Response{
		Code: code,
		Msg:  msg,
		Data: data,
	}

	switch ctx.ContentType() {
	case gin.MIMEJSON:
		ctx.JSON(code, resp)
	case gin.MIMEXML, gin.MIMEXML2:
		ctx.XML(code, xmlResponse{
			Response: resp,
		})
	default:
		ctx.JSON(http.StatusOK, resp)
	}
}

func (this *Controller) ResponseAndAbort(ctx *gin.Context, code int, msg string, data interface{}) {
	ctx.Abort()
	this.Response(ctx, code, msg, data)
}

func (this *Controller) TraceId(ctx *gin.Context) int64 {
	return helper.GetTraceId(ctx)
}

func (this *Controller) GetInfoParams(ctx *gin.Context) (string, error) {
	id := ctx.DefaultQuery("id", "")
	if id == "" {
		return "", fmt.Errorf("id is required")
	}

	return id, nil
}

func (this *Controller) GetIndexParams(ctx *gin.Context) (page int64, pageSize int64, where map[string]interface{}, orders []string) {
	page = helper.ToInt(ctx.DefaultQuery("page", "1"))
	pageSize = helper.ToInt(ctx.DefaultQuery("pageSize", "15"))

	where = make(map[string]interface{})
	//如：{"id": ["35", "45"], "is_on": 1}
	whereStr := ctx.DefaultQuery("where", "")
	if whereStr != "" {
		_ = json.Unmarshal([]byte(whereStr), &where)
	}

	//如：["id", "-is_on"]; -为desc，其他为asc
	orderStr := ctx.DefaultQuery("order", "")
	orders = []string{}
	if orderStr != "" {
		_ = json.Unmarshal([]byte(orderStr), &orders)
	}
	return
}

func (this *Controller) GetUpOrDownParams(ctx *gin.Context) (value uint8, err error) {
	input := struct {
		logic.XmlInput
		Value uint8 `json:"value" xml:"value" form:"value" binding:"max=1,min=0" msg:"value值必须为0或1"`
	}{}

	if err = ctx.ShouldBind(&input); err != nil {
		err = this.FormatError(input, err)
		return
	}

	value = input.Value
	return
}
